Building essentia.js from source
You can find pre-compiled builds of essentia.js
here.
- Clone or download the essentia.js repository.
Easiest way
-
Pull official essentia-emscripten docker image.
docker pull mtgupf/essentia-emscripten:latest
-
Build
essentia.js
inside the docker containerdocker run --rm -v `pwd`:/essentia/ mtgupf/essentia-emscripten:latest /essentia/build-libs.sh
OR
Step-by-step
-
Run the following command to install all the Node.js dependencies.
npm install
You need to have a local installation of Node.js (v12.9.1 or later)
Generate essentia-wasm backend and bindings.
In order to build the associated essentia.js
builds we need to compile the essentia C++ library to WebAssembly target using Emscripten.
In order to make the process easier, you could use the docker image (recommended) or build everything from the source on your local system.
(Optional)
We use some python scripts to automatically generate the C++ wrappers and the JS bindings from the Essentia upstream documentation using the Essentia python bindings. You need to have a local installation of Python with the required dependencies to re-generate the JS bindings and typescript wrapper source code.
pip install -r src/python/requirements.txt
Using docker
You need to have a local installation of docker.
-
Pull the official
essentia-emscripten
docker image.docker pull mtgupf/essentia-emscripten:latest
-
Clone or download the essentia.js repo.
-
cd
to repo and mount the current directory as volume and runbuild-bindings.sh
inside the docker container and check the new builds at thedist/
directory.docker run --rm -v `pwd`:/srv/workspace/ \ mtgupf/essentia-emscripten:latest \ /srv/workspace/build-bindings.sh \ Makefile.essentiajs
OR
Building from source locally
-
Install emscripten.
-
Clone the essentia repository.
git clone https://github.com/MTG/essentia.git
-
Install the required 3rd party dependencies for essentia. Check the instructions here.
-
Compile essentia C++ library with the emscripten compiler. Check essentia documentation for more details.
# configure build settings for essentia using kissfft emconfigure sh -c './waf configure --prefix=$EMSCRIPTEN/system/local/ --build-static --lightweight= --fft=KISS --emscripten' # compile and build essentia emmake ./waf # (you might need sudo rights) emmake ./waf install
-
Clone or download the essentia.js repo.
-
Finally,
cd
to repo and build theessentia.js
bindings using one of the following commands. Check the new builds at thedist/
directory.Spawn a subshell inside the emscripten
emconfigure
in order to properlly access the emscripten variables.emconfigure sh -c './build-bindings.sh Makefile.essentiajs'
Note: make you added the emscripten env variables to your bash profile.
Build essentia.js API and dist files
Build the final essentia.js JS API dist by running the following command.
npm run build-js-api
Once all the above-mentioned steps are done successfuly, you will find the final build essentia in the dist
folder.
Build documentation
Build essentia.js API documentation using the following the command.
npm run build-api-docs
You can find the documentation files in the out
directory once it's done.
Customizing your essentia.js builds
You can make customised builds of essentia.js for only a set of selected essentia standard algoithms using the code_generator.py python script which creates cpp source code and bindings for all the algos listed in included_algos.md. This list of included algorithms can be customised using the configure_bindings.py script.
cd src/python
# configure default list of algorithms for creating the js bindings
python configure_bindings.py
# OR
# specify a list of algorithms for which you need to create the js bindings
python configure_bindings.py -i "['Key', 'HPCP']"
# OR
# you can specify the algorithm list by a text file with name of
# algorithms seperated by a new line.
python configure_bindings.py -i your_included_algos_list.txt
# for more cli options
python configure_bindings.py -h
Advanced
Writing custom essentia C++ extractor and cross-compile to JS for better performance on JS
You could also write your own customised essentia feature extractor in C++ and cross-compile to WASM using emscripten and our toolchain following the build instructions.
A custom C++ feature extractors can be write and cross-compiled to JS using our given template and examples in cases where the performance of feature extractors are significant. The essentia_custom_extractor.h
, essentia_custom_extractor.cpp
and bindings_extractor.cpp
files demonstrates an example of writing a custom C++ extractor which can be cross-compiled and run on JS for both real-time and offline feature extraction cases. In this particular example the extractor computes Log-scaled MelSpectrogram for a given audio channel data input from the WebAudio API or any other sources. The extractor provide a object-oriented interface which can be used to configure
, compute
, reset
and shutdown
the algorithms as the user needs (relevant for better performance in batch or real-time feature extractors).
Usage
- Build the custom cpp extractor using the given Makefile. Make sure you have the required dependencies for building Essentia WASM.
make
- Usage on JavaScript would be like
// import essentia-wasm backend
import { EssentiaWASM } from 'essentia-custom-extractor.module.js';
// create an instance of our custom 'LogMelSpectrogramExtractor'
// by passing our configuration settings for the given parameters
const extractor = new EssentiaWASM.LogMelSpectrogramExtractor(1024, // frameSize
512, // hopSize
96, // numBands
'hann'); // windowType
// Use the Web Audio API to decode the audio channel data from an url of a audio file
const audioURL = "https://freesound.org/data/previews/328/328857_230356-lq.mp3";
const audioContext = new AudioContext();
const response = await fetch(audioURL);
const arrayBuffer = await response.arrayBuffer();
const audioBuffer = await audioContext.decodeAudioData(arrayBuffer);
// getChannelData of channel number 0 (since it's a mono audio signal)
const audioData = audioBuffer.getChannelData(0);
// Now, let's compute the log-mel spectrogram feature for the given audio input
let melSpectrogram = extractor.compute(audioData);
// reset the internal states of the algorithms used in the extractor
extractor.reset();
// reconfigure our extractor with new parmeter settings
extractor.configure(1024, 512, 128, 'hann');
// compute with new settings
let melSpectrogram = extractor.compute(audioData);
// delete algorithms and free memory after it's use
extractor.shutdown();
extractor.delete();